package ar.edu.caece.pl.asin.manager.impl;

import ar.edu.caece.pl.alex.model.IDictionary;
import ar.edu.caece.pl.alex.model.IToken;
import ar.edu.caece.pl.alex.model.impl.Dictionary;
import ar.edu.caece.pl.alex.model.impl.Token;
import ar.edu.caece.pl.asin.manager.IAnalizadorSintactico;
import ar.edu.caece.pl.asin.manager.IErrorManager;
import ar.edu.caece.pl.asin.model.ITokenStream;

public abstract class AbstractAnalizadorSintactico implements IAnalizadorSintactico {
	
	/* ACTORES PRINCIPALES */
	protected IErrorManager em;
	protected ITokenStream tokenStream;
	
	/* ELEMENTOS AUXILIARES */
	protected IDictionary dic = Dictionary.getInstance();
	private static final String INIT_ERROR = "No se asigno fuente para leer";
	protected boolean debugMode;
	
	/* INICIALIZACION */
	
	public AbstractAnalizadorSintactico ( ITokenStream ts, boolean debugMode ) {
		
		if (ts == null) {
			
			throw new IllegalArgumentException( INIT_ERROR );
		}
		
		this.tokenStream = ts;
		this.debugMode = debugMode;
		
		//Inicializo el ErrorManager
		em= ErrorManager.getInstance(debugMode);
	}

	//Para sobrescribir
	public abstract boolean reconocer();
	
	protected IToken getTokenActual() {
		
		return this.tokenStream.getTokenActual();
	}
	
	protected IToken getTokenSiguiente() {
		
		return this.tokenStream.getTokenSiguiente();
	}
	
	/** Lee y debuguea. Ademas es privado porque solo lo llamara this.reconocerToken() */
	private void avanzar() {
		// Avanzo
		tokenStream.leer();

		//Agrego info de debug del token leido
		em.debug( this.getTokenActual() );
	}
	
	protected boolean reconocerToken(int tokenType) {
		
		return (this.dic.isValid(tokenType))?
			this.reconocerToken(new Token(tokenType)):
			false;
	}
	
	protected boolean reconocerToken(String palabraReservada) {
		
		return (this.dic.isValid(palabraReservada))?
				this.reconocerToken(new Token(palabraReservada)):
				false;
	}
	
	private boolean reconocerToken(IToken token) {
		
		boolean recognized = true;
		
		if (this.getTokenSiguiente().equals(token)) {
			
			this.avanzar();
			
		} else {
			
			em.error("Se esperaba "+token.getTokenText(), this.getTokenSiguiente());
			recognized = false;
			
			em.recover(this.getClass(), this.tokenStream);
		}
		return recognized;
	}
}
